#ifndef DELEGATE_H
#define DELEGATE_H

#include "slot.h"

/*!
 *	\class 	AbstractDelegate()
 *	\brief	Classe virtuelle pure qui n'a pour but que d'autoriser le polymorphisme en permettant de stocker plusieurs
 *              délégués aux patrons différents (template) à l'intérieur d'un std::vector<AbstractDelegate *>
 */

class AbstractDelegate	
{
	public :
	
        std::vector<AbstractSlot *> Slots;  /*!< Slots (objet + méthode) qui s'éxécuteront lorsque le signal retournera "vrai"	*/
	
	AbstractDelegate(){};

	/*!
	 *	\fn virtual void Run()
	 *	\brief	Exécute toutes les méthodes connectés au délégués
	 */

	virtual void Run()=0;

	/*!
 	 * 	\fn virtual void Update()
	 *	\brief 		Exécute la méthode signal du délégué, si cette dernière renvoie vrai,
	 * 		 	toutes les méthodes des slots branché au signal seront exécutés
	 */

	virtual void Update()=0;
	
        /*!
         * 	\fn Connect(int (Z::*apSlot), Z *aSlot)
         * 	\brief	Ajoute un slot (fonction qui devra s'éxécuter lorsque le signal renvera la valeur "vrai"),
                au délégué courant
         */

        template <class Z>
        void Connect( Slot<Z> * aSlot)
	{
                Slots.push_back(aSlot);
	}	
};

/*!
 *	\class Delegate : AbstractDelegate
 *	\brief Enregistre un signal, représenté par un pointeur de fonction membre
 */

template <class T>
class Delegate : public AbstractDelegate	
{
	public :
		
	/*************************************************************/
        /*					Propriétés	     */
	/*************************************************************/
	
        T * objetSignal;        /*!< Pointeur vers l'objet de base	*/
        int (T::*pSignal)();    /*!< Pointeur de la fonction signal 	*/
	
	/*************************************************************/
        /*					Constructeur         */
	/*************************************************************/

        Delegate(int (T::*apSignal)(),T * ref);
        Delegate(int (T::*apSignal)(int),T *ref);
        Delegate(int (T::*apSignal)(float),T *ref);
	/*************************************************************/
        /*					Méthodes	  */
	/*************************************************************/
	
	void Update();
	void Run();

};

template <class T>
Delegate<T>::Delegate(int (T::*apSignal)(),T * ref) : objetSignal(ref), pSignal(apSignal){}

template <class T>
void Delegate<T>::Update()
{


	if((objetSignal->*pSignal)())
	{

		Run();
	}
}

template <class T>
void Delegate<T>::Run()
{
        for(int i=0;i<Slots.size();i++)
	{
                Slots[i]->Run();
	}
}

#endif
